﻿using System.Reflection;

namespace ELF.Modules
{
    internal class ModuleSortedHelper
    {
        internal static List<Type> GetSortedModules(Type startupModuleType)
        {
            var context = new ModuleLoadContext();

            // 添加启动模块及其依赖
            AddModuleToContext(context, startupModuleType);

            // 检查循环依赖
            CheckCircularDependencies(context.AllModules);

            // 拓扑排序
            return SortModules(context.AllModules);
        }

        private static void AddModuleToContext(ModuleLoadContext context, Type moduleType)
        {
            context.AddModule(moduleType);

            // 如果已经加载过，不再处理其依赖
            if (context.LoadedModules.Contains(moduleType))
            {
                return;
            }

            context.LoadedModules.Add(moduleType);

            // 处理依赖项
            var dependsOnAttributes = moduleType
                .GetCustomAttributes<DependsOnAttribute>(inherit: true);

            foreach (var dependsOnAttribute in dependsOnAttributes)
            {
                foreach (var dependedModuleType in dependsOnAttribute.DependedModuleTypes)
                {
                    AddModuleToContext(context, dependedModuleType);
                }
            }
        }

        private static void CheckCircularDependencies(List<Type> allModules)
        {
            var graph = new Dictionary<Type, HashSet<Type>>();

            // 构建依赖图
            foreach (var module in allModules)
            {
                var dependencies = module.GetCustomAttributes<DependsOnAttribute>(true)
                    .SelectMany(attr => attr.DependedModuleTypes)
                    .ToList();

                graph[module] = new HashSet<Type>(dependencies);
            }

            // 检查循环依赖
            var visited = new HashSet<Type>();
            var recursionStack = new HashSet<Type>();

            foreach (var module in graph.Keys)
            {
                if (HasCycle(module, graph, visited, recursionStack))
                {
                    throw new InvalidOperationException($"发现循环模块依赖: {string.Join(" -> ", recursionStack)}");
                }
            }
        }

        private static bool HasCycle(Type module,
            Dictionary<Type, HashSet<Type>> graph,
            HashSet<Type> visited,
            HashSet<Type> recursionStack)
        {
            if (recursionStack.Contains(module))
            {
                return true;
            }

            if (visited.Contains(module))
            {
                return false;
            }

            visited.Add(module);
            recursionStack.Add(module);

            if (graph.TryGetValue(module, out var dependencies))
            {
                foreach (var dependency in dependencies)
                {
                    if (HasCycle(dependency, graph, visited, recursionStack))
                    {
                        return true;
                    }
                }
            }

            recursionStack.Remove(module);
            return false;
        }

        private static List<Type> SortModules(List<Type> modules)
        {
            var graph = new Dictionary<Type, HashSet<Type>>();
            var inDegree = new Dictionary<Type, int>();

            // 初始化图和入度
            foreach (var module in modules)
            {
                graph[module] = new HashSet<Type>();
                inDegree[module] = 0;
            }

            // 构建依赖图
            foreach (var module in modules)
            {
                var dependsOnAttributes = module.GetCustomAttributes<DependsOnAttribute>(true);
                foreach (var attr in dependsOnAttributes)
                {
                    foreach (var dependency in attr.DependedModuleTypes)
                    {
                        if (graph.TryGetValue(dependency, out var dependents))
                        {
                            if (dependents.Add(module))
                            {
                                inDegree[module]++;
                            }
                        }
                    }
                }
            }

            // 拓扑排序
            var queue = new Queue<Type>(inDegree.Where(x => x.Value == 0).Select(x => x.Key));
            var sorted = new List<Type>();

            while (queue.Count > 0)
            {
                var module = queue.Dequeue();
                sorted.Add(module);

                foreach (var dependent in graph[module])
                {
                    inDegree[dependent]--;
                    if (inDegree[dependent] == 0)
                    {
                        queue.Enqueue(dependent);
                    }
                }
            }

            if (sorted.Count != modules.Count)
            {
                throw new InvalidOperationException("模块依赖关系存在循环或无效依赖");
            }

            return sorted;
        }
    }

    public class ModuleLoadContext
    {
        public List<Type> AllModules { get; } = new();
        public List<Type> LoadedModules { get; } = new();

        public void AddModule(Type moduleType)
        {
            if (!typeof(IModule).IsAssignableFrom(moduleType))
            {
                throw new ArgumentException($"类型 {moduleType.Name} 必须实现 IModule 接口");
            }

            if (!AllModules.Contains(moduleType))
            {
                AllModules.Add(moduleType);
            }
        }
    }
}
